#include "SceneVisibility.h"

#include "Runtime/Rendering/MeshPassProcessor.h"
#include "Runtime/Rendering/PrimitiveSceneInfo.h"
#include "Runtime/Rendering/SceneRendering.h"
#include "Runtime/Thread/Task.h"

namespace Alice
{
    FVisibilityTaskData::FVisibilityTaskData(CGICommandListImmediate* inCGICommandList, SceneRenderer* inSceneRenderer)
        :mCGICommandList(inCGICommandList),mScene(inSceneRenderer->Scene),mViews(inSceneRenderer->mAllViews),mSceneRenderer(inSceneRenderer)
    {
        
    }

    void FVisibilityTaskData::LaunchVisibilityTasks(const TaskHandle* inBeginInitVisibilityPrerequisites)
    {
        FVisibilityViewPacket*visibilityViewPacket=new FVisibilityViewPacket(*this,*mScene,*mViews[0],0);
        visibilityViewPacket->mRelevance.Context->AddPrimitive(0);
        visibilityViewPacket->mRelevance.Context->Finalize();
    }
    void FVisibilityTaskData::ProcessRenderThreadTasks()
    {
        
    }
    void FVisibilityTaskData::FinishGatherDynamicMeshElements()
    {
        SetupMeshPasses();
    }

    void FVisibilityTaskData::SetupMeshPasses()
    {
        uint32 viewCount=mViews.size();
        for(uint32 viewIndex=0;viewIndex<viewCount;viewIndex++)
        {
            ViewInfo*view=mViews[viewIndex];
            FViewCommands*viewCommands=mDynamicMeshElements.mViewCommandsPerView[viewIndex];
            mSceneRenderer->SetupMeshPass(*view,*viewCommands);
        }
    }
    void FVisibilityTaskData::Finish()
    {
        
    }
    FDrawCommandRelevancePacket::FDrawCommandRelevancePacket()
    {
        
    }
    void FDrawCommandRelevancePacket::AddCommandsForMesh(int32 PrimitiveIndex,
            const PrimitiveSceneInfo* InPrimitiveSceneInfo,
            const FStaticMeshBatchRelevance& StaticMeshRelevance,
            const FStaticMeshBatch& StaticMesh,
            //EMeshDrawCommandCullingPayloadFlags CullingPayloadFlags,
            const Scene* Scene,
            bool bCanCache,
            EMeshPass::Type PassType)
    {
        const int32 StaticMeshCommandInfoIndex = StaticMeshRelevance.GetStaticMeshCommandInfoIndex(PassType);
        const FCachedMeshDrawCommandInfo* CachedMeshDrawCommand = InPrimitiveSceneInfo->mStaticMeshCommandInfos[StaticMeshCommandInfoIndex];
        const FCachedPassMeshDrawList& SceneDrawList = Scene->mCachedPassMeshDrawList[PassType];
        
        FVisibleMeshDrawCommand*visibleMeshDrawCommand=new FVisibleMeshDrawCommand;
        const FMeshDrawCommand& MeshDrawCommand = SceneDrawList.MeshDrawCommands[CachedMeshDrawCommand->CommandIndex];
        FMeshDrawCommandPrimitiveIdInfo idInfo;
        visibleMeshDrawCommand->Setup(&MeshDrawCommand,idInfo,-1,ERasterizerFillMode::FM_Solid,ERasterizerCullMode::CM_CCW,EFVisibleMeshDrawCommandFlags::All,CachedMeshDrawCommand->SortKey);
        mVisibleCachedDrawCommands[PassType].push_back(visibleMeshDrawCommand);
    }
    FRelevancePacket::FRelevancePacket(FVisibilityTaskData& InTaskData, const ViewInfo& InView, int32 InViewIndex, uint8* InMarkMasks, const FTask& PrerequisitesTask)
        :mScene(InTaskData.mScene)
    {
        
    }
    void FRelevancePacket::ComputeRelevance(FDynamicPrimitiveIndexList& DynamicPrimitiveIndexList)
    {
        uint32 inputNum=Input.size();
        for(uint32 index=0;index<inputNum;index++)
        {
            PrimitiveSceneInfo*primitiveSceneInfo=mScene->mPrimitives[index];
            uint32 staticMeshCount=primitiveSceneInfo->mStaticMeshRelevances.size();
            for(uint32 staticMeshIndex=0;staticMeshIndex<staticMeshCount;staticMeshIndex++)
            {
                const FStaticMeshBatchRelevance* staticMeshRelevance = primitiveSceneInfo->mStaticMeshRelevances[staticMeshIndex];
                const FStaticMeshBatch* staticMesh = primitiveSceneInfo->mStaticMeshes[staticMeshIndex];
                mDrawCommandPacket.AddCommandsForMesh(0,primitiveSceneInfo,*staticMeshRelevance,*staticMesh,mScene,true,EMeshPass::BasePass);
            }
        }
    }
    FComputeAndMarkRelevance::FComputeAndMarkRelevance(FVisibilityTaskData& inVisibilityTaskData, Scene* inScene, ViewInfo& inView, uint8 inViewIndex, const FTask& inPreprequisitesTask)
        :TaskData(inVisibilityTaskData),mScene(inScene),View(inView),PrerequisitesTask(inPreprequisitesTask)
    {
        
    }
    
    void FComputeAndMarkRelevance::AddPrimitive(int32 Index)
    {
        FRelevancePacket*relevancePacket=new FRelevancePacket(TaskData,View,0,nullptr,PrerequisitesTask);
        relevancePacket->Input.push_back(Index);
        mRelevancePackets.push_back(relevancePacket);
    }
    void FComputeAndMarkRelevance::Finalize()
    {
        FDynamicPrimitiveIndexList DynamicPrimitiveIndexList;
        mRelevancePackets[0]->ComputeRelevance(DynamicPrimitiveIndexList);
    }

    FVisibilityViewPacket::FVisibilityViewPacket(FVisibilityTaskData& inTaskData, Scene& InScene, ViewInfo& inViewInfo, int32 ViewIndex)
        :TaskData(inTaskData), mScene(InScene),mViewInfo(inViewInfo)
    {
        
    }
    void FVisibilityViewPacket::BeginInitVisibility()
    {
        EventTask RelevancePrereqs;
        mViewInfo.mPrimitiveVisibilityMap.resize(mScene.mPrimitives.size());
        mRelevance.Context=new FComputeAndMarkRelevance(TaskData, &mScene, mViewInfo, 0, RelevancePrereqs);
        mViewInfo.mPrimitiveVisibilityMap[0]=true;
    }
}
